package org.mobicents.example;

import gov.nist.javax.sip.Utils;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.header.CSeqHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import javax.slee.ActivityContextInterface;
import javax.slee.RolledBackContext;
import javax.slee.SbbContext;
import javax.slee.serviceactivity.ServiceActivity;
import javax.slee.serviceactivity.ServiceActivityFactory;
import javax.slee.facilities.Tracer;
import net.java.slee.resource.sip.SleeSipProvider;

public abstract class RootSbb implements javax.slee.Sbb {
	
	public boolean DEBUGMODE = false;

	private SbbContext sbbContext = null; // This SBB's context		
	private Context sbbEnv;
	private SleeSipProvider provider = null;
	//log facility instead of java.util or log4j
	private Tracer logger = null;
	// -- EVENT HANDLERS
	private AddressFactory addressFectory;
	private HeaderFactory headerFactory;
	private MessageFactory messageFactory;
	
	public void onServiceStartedEvent(javax.slee.serviceactivity.ServiceStartedEvent event,ActivityContextInterface aci) {
		
		if(logger.isFineEnabled()) {
			logger.fine("onServiceStartedEvent(event=" + event.toString() + ",aci="
				+ aci.toString() + ")");
		}
		
		try {
			Context myEnv = (Context) new InitialContext().lookup("java:comp/env");
			ServiceActivity sa = ((ServiceActivityFactory) myEnv
					.lookup("slee/serviceactivity/factory")).getActivity();
			if (sa.equals(aci.getActivity())) {
				// it's this service that is starting
				logger.info("service activated...");
				logger.info("Hello World!!!");
			}		
			// don't want to receive further events on this activity
			aci.detach(this.sbbContext.getSbbLocalObject());
			
		} catch (Exception e) {
			logger.severe("Can't handle service started event.", e);
		}
	}
	
	public void onRegisterEvent(RequestEvent event, ActivityContextInterface aci) {
		logger.info("REGISTER REQUEST RECEIVED AT MY SBB");
		Request register = event.getRequest();
		ServerTransaction st = event.getServerTransaction();
		FromHeader from = (FromHeader) register.getHeader(FromHeader.NAME);
		ContactHeader contact = (ContactHeader) register.getHeader(ContactHeader.NAME);
		
		logger.info("SENDING RESPONSE TO THE REGISTER REQUEST");
		try {
			st.sendResponse(messageFactory.createResponse(Response.OK, register));
			logger.info("SENDING AN INSTANT MESSAGE TO THE CLIENT");
			
			//----------------------------------------------- Start debug
			if(DEBUGMODE){
				if(addressFectory == null)
					logger.info("A Address Factory e null");
				else
					logger.info("A Address Factory NAO null");
			}
			
			//----------------------------------------------- End debug
			
			Address fromNameAddress = addressFectory.createAddress("sip:mobicents-jain-slee@mobicents.org");
			fromNameAddress.setDisplayName("Mobicents JAIN SLEE TITURIAL");
			
			FromHeader fromHeader = headerFactory.createFromHeader(fromNameAddress, Utils.getInstance().generateTag());
			List<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(1);
			ListeningPoint listeningPoint = provider.getListeningPoints()[0];
			ViaHeader viaHeader = provider.getHeaderFactory().createViaHeader(listeningPoint.getIPAddress(), listeningPoint.getPort(), listeningPoint.getTransport(), null);
			viaHeaders.add(viaHeader);
			
			ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("text", "plain");
			CSeqHeader cSecHeader = headerFactory.createCSeqHeader(2L, Request.MESSAGE);
			MaxForwardsHeader maxForwardsHeader = headerFactory.createMaxForwardsHeader(70);
			provider.getNewClientTransaction(messageFactory.createRequest(contact.getAddress().getURI(), Request.MESSAGE, headerFactory.createCallIdHeader("mobicents "+System.currentTimeMillis()), cSecHeader, fromHeader, headerFactory.createToHeader(from.getAddress(), null), viaHeaders, maxForwardsHeader, contentTypeHeader, "Welcome to Mobicents First Demo!!!")).sendRequest();
			
		} catch (SipException e) {
			logger.info("[RootSbb.onServiceStartedEvent.SipException]:" + e.getMessage(), e.getCause());
			e.printStackTrace();
		} catch (InvalidArgumentException e) {
			logger.info("[RootSbb.onServiceStartedEvent.InvalidArgumentException]:" + e.getMessage(), e.getCause());
			e.printStackTrace();
		} catch (ParseException e) {
			logger.info("[RootSbb.onServiceStartedEvent.ParseException]:" + e.getMessage(), e.getCause());
			e.printStackTrace();
		}
		logger.info("REQUEST GREETING SENT!!!  :D");
	}
	
	// -- SBB OBJECT LIFECYLE METHODS
	
	/**
	 * Called when an sbb object is instantied and enters the pooled state.
	 */
	public void setSbbContext(SbbContext context) {
		this.logger = context.getTracer(RootSbb.class.getSimpleName());
		if (logger.isFineEnabled()) {
			logger.fine("setSbbContext(...)");
		}
		this.sbbContext = context;
		try {
			sbbEnv = (Context) new InitialContext().lookup("java:comp/env");
			provider = (SleeSipProvider) sbbEnv.lookup("slee/resources/jainsip/1.2/provider");
			messageFactory = provider.getMessageFactory();
			headerFactory = provider.getHeaderFactory();
			addressFectory = provider.getAddressFactory();
			logger.info("setSbbContex(...)");
		} catch (NamingException e) {
			logger.info("[RootSbb.onServiceStartedEvent.NamingException]:", e.getCause());
			e.printStackTrace();
		}
		logger.info("NAO DEU BODES!!!  :D");		
	}

	public void unsetSbbContext() {
		if (logger.isFineEnabled()) {
			logger.fine("unsetSbbContext()");
		}
		this.sbbContext = null;
	}

	public void sbbCreate() throws javax.slee.CreateException {
		if (logger.isFineEnabled()) {
			logger.fine("sbbCreate()");
		}
	}

	public void sbbPostCreate() throws javax.slee.CreateException {
		if (logger.isFineEnabled()) {
			logger.fine("sbbPostCreate()");
		}
	}

	public void sbbActivate() {
		if (logger.isFineEnabled()) {
			logger.fine("sbbActivate()");
		}
	}

	public void sbbPassivate() {
		if (logger.isFineEnabled()) {
			logger.fine("sbbPassivate()");
		}
	}

	public void sbbRemove() {
		if (logger.isFineEnabled()) {
			logger.fine("sbbRemove()");
		}
	}

	public void sbbLoad() {
		if (logger.isFineEnabled()) {
			logger.fine("sbbLoad()");
		}
	}

	public void sbbStore() {
		if (logger.isFineEnabled()) {
			logger.fine("sbbStore()");
		}
	}

	public void sbbExceptionThrown(Exception exception, Object event,
			ActivityContextInterface activity) {
		if (logger.isFineEnabled()) {
			logger.fine("sbbExceptionThrown(exception=" + exception.toString()
					+ ",event=" + event.toString() + ",activity="
					+ activity.toString() + ")");
		}
	}

	public void sbbRolledBack(RolledBackContext sbbRolledBack) {
		if (logger.isFineEnabled()) {
			logger.fine("sbbRolledBack(sbbRolledBack=" + sbbRolledBack.toString()
				+ ")");
		}
	}


}